package org.springonrails.appgen;

import java.io.File;
import java.io.FileWriter;
import java.io.FilenameFilter;
import java.io.InputStream;
import java.util.ArrayList;
import java.util.List;
import java.util.Properties;

import org.apache.commons.io.IOUtils;
import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;
import org.springonrails.RailsException;
import org.springonrails.db.DBEntityReverseMapper;
import org.springonrails.model.Entity;
import org.springonrails.parser.EntityMapDomParser;
import org.springonrails.template.BuiltInFreeMarkerSourceGenerator;
import org.springonrails.template.SourceGenerator;
import org.springonrails.template.TemplateActivator;

public class SpringOnRails 
{
	
	private static Log log = LogFactory.getLog(SpringOnRails.class);
	public final static String ENTITY_MAP_LOCATION = "entityMap";
	
	
	public final static String TEMPLATE_PLUGIN_DIR = "plugins";
	
	
	private String entityMappingLocation       = null;
	private String groupId                     = "com.asksunny.demo";
	private String outputDir                   = "target";
	private String artifactId                  = "demo";
	private final Properties properties;
	private final List<Entity> entities;
	
	private SourceGenerator sourceGenerator = null;
	
	public SpringOnRails()
	{
		properties            = new Properties();
		properties.putAll(System.getProperties());
		entities              = new ArrayList<Entity>();		
	}
	
	protected void initTemplateActivator()
	{
		File pluginDirs = new File(TEMPLATE_PLUGIN_DIR);
		if(pluginDirs.exists() && pluginDirs.isDirectory()){		
			File[] templatePlugins = pluginDirs.listFiles(new FilenameFilter(){
				public boolean accept(File dir, String name) {				
					boolean isJar = name.toLowerCase().endsWith(".jar");				
					return isJar;
				}
			});
			
			for (File file : templatePlugins) 
			{			
				ClassLoader loader = TemplatePluginClassLoader.createInstance(file.toURI());
				
				InputStream in = loader.getResourceAsStream("/META/activator");
				if(in==null) continue;
				try{
					String clazz = IOUtils.toString(in).trim();
					TemplateActivator activator = (TemplateActivator)loader.loadClass(clazz).newInstance();
					sourceGenerator = activator.getGenerator(properties);					
				}catch (Exception e) {
					log.warn("Invalid plugins file>>" + file.getAbsolutePath(), e);
					continue;
				}			
				if( sourceGenerator!=null ) break;		
			}
		}		
		if( sourceGenerator==null ){
			sourceGenerator = new BuiltInFreeMarkerSourceGenerator(this.properties);
		}	
	}
	
	
	public void run()
	{
		initEntityMapping();
		initTemplateActivator();
		DBEntityReverseMapper reverseMapper = new DBEntityReverseMapper(properties);
		entities.addAll(reverseMapper.getEntities());
				
		if(properties.getProperty("createMap", "false").equalsIgnoreCase("true")){
			genReverseMapping();
		}else{		
			sourceGenerator.setArtifactId(this.artifactId);
			sourceGenerator.setGroupId(this.groupId);
			sourceGenerator.setOutputDirectory(this.outputDir);
			sourceGenerator.generateSource(entities);
		}
	}
	
	protected void genReverseMapping()
	{
				
		File file = new File("reverse-mapping.xml");
		if(entityMappingLocation!=null){
			File dir = (new File(entityMappingLocation)).getParentFile();
			file = new File(dir, "reverse-mapping-" + (new File(entityMappingLocation)).getName());
		}
		FileWriter fw = null; 
	    try{
			fw = new FileWriter(file);
			for (Entity entity : entities) {
				fw.write(entity.toString());
				fw.flush();
			}			
		}catch(Exception ex){
			log.error("Failed to create reverse mapping file", ex);
		}finally{
			if(fw!=null)try{fw.close();}catch(Exception ex){;}
		}
		
	}
	
	
	protected void initEntityMapping()
	{
		if(entityMappingLocation==null){
			entityMappingLocation = properties.getProperty(ENTITY_MAP_LOCATION);
		}
		if(entityMappingLocation==null) throw new RailsException("Unable to find entity mapping file.");
	    EntityMapDomParser parser = new EntityMapDomParser(entityMappingLocation);
	    this.properties.putAll(parser.getAdditionalProperties());
		this.entities.addAll(parser.getEntities());	    
	}
	
	
		
	public String getEntityMappingLocation() 
	{
		return entityMappingLocation;
	}
	public void setEntityMappingLocation(String entityMappingLocation) 
	{
		this.entityMappingLocation = entityMappingLocation;
	}
	public String getGroupId() {
		return groupId;
	}
	public void setGroupId(String groupId) {
		this.groupId = groupId;
	}
	public String getOutputDir() {
		return outputDir;
	}
	public void setOutputDir(String outputDir) {
		this.outputDir = outputDir;
	}
	public String getArtifactId() {
		return artifactId;
	}
	public void setArtifactId(String artifactId) {
		this.artifactId = artifactId;
	}
	
	
	
}
